package com.dc.free.plugin;

import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <ul>
 * <li><b>扫描器</b></li>
 * <li>1.根据unionCode登记扫描信息，创建对应Awaiter，线程挂起</li>
 * <li>2.扫描获取unionCode，获取Awaiter，唤醒线程，执行下面工作</li>
 * <li>3.定期清除过期Awaiter</li>
 * </ul>
 * @author quan
 *
 * @param <T>
 */
public abstract class ScannerPlugin<T> {
	
	final public static class Awaiter {
		private Lock lock = new ReentrantLock();
		private Condition condition = lock.newCondition();
		private Date date = new Date();
		private String data;
		
		public Awaiter() {
			super();
		}
		
		public Awaiter(String data) {
			super();
			this.data = data;
		}

		public Lock getLock() {
			return lock;
		}
		
		public Condition getCondition() {
			return condition;
		}

		public Date getDate() {
			return date;
		}
		
		public long getDateInterval() {
			return new Date().getTime() - date.getTime();
		}

		public String getData() {
			return data;
		}
		
	}
	
	final public static class Record {
		private String code;
		private Long interval;
		
		public Record(String code, Long interval) {
			super();
			this.code = code;
			this.interval = interval;
		}

		public String getCode() {
			return code;
		}

		public void setCode(String code) {
			this.code = code;
		}

		public Long getInterval() {
			return interval;
		}

		public void setInterval(Long interval) {
			this.interval = interval;
		}
		
	}
	
	//扫描间隔(单位毫秒)
	private volatile int scanIntervalWithMsec = 1 * 1000;
	//清理间隔（单位毫秒）
	private volatile int cleanIntervalWithMsec = 60 * 1000;
	//启动标识
	private volatile boolean isRunning;
	protected static final ExecutorService service = Executors.newFixedThreadPool(20);
	private volatile Map<String, Awaiter> awaiters = new ConcurrentHashMap<String, Awaiter>();
	private int recordNumber = 100;
	private volatile List<Record> records = new LinkedList<Record>();
	
	
	public ScannerPlugin() {} 
	
	/**
	 * 设置扫描时间间隔
	 * @param scanIntervalWithMsec  单位毫秒
	 */
	public void setScanIntervalWithMsec(int scanIntervalWithMsec) {
		this.scanIntervalWithMsec = scanIntervalWithMsec;
	}
	
	/**
	 * 设置清理时间间隔
	 * @param cleanIntervalWithMsec  单位毫秒
	 */
	public void setCleanIntervalWithMsec(int cleanIntervalWithMsec) {
		this.cleanIntervalWithMsec = cleanIntervalWithMsec;
	}
	
	public boolean isRunning() {
		return isRunning;
	}

	public abstract List<T> scan();
	
	public abstract String getUnionCode(T t);
	
	public abstract void clean(String[] unionCodes);
	
	public void setRecordNumber(int recordNumber) {
		this.recordNumber = recordNumber;
	}

	/**
	 * 根据unionCode注册Awaiter
	 * @param unionCode  唯一标识
	 * @throws InterruptedException
	 */
	public void putAwaiter(String unionCode) throws InterruptedException {
		if(unionCode == null || unionCode=="" || awaiters.containsKey(unionCode)) 
			throw new IllegalArgumentException("unionCode为空或者已经存在");
		Awaiter awaiter = new Awaiter();
		awaiters.put(unionCode, awaiter);
		Lock lock = awaiter.getLock();
		lock.lock();
		awaiter.getCondition().await();
		lock.unlock();
	}
	
	public void putAwaiter(String unionCode, String data) throws InterruptedException {
		if(unionCode == null || unionCode=="" || awaiters.containsKey(unionCode)) 
			throw new IllegalArgumentException("unionCode为空或者已经存在");
		Awaiter awaiter = new Awaiter(data);
		awaiters.put(unionCode, awaiter);
		Lock lock = awaiter.getLock();
		lock.lock();
		awaiter.getCondition().await();
		lock.unlock();
	}
	
	/**
	 * 解锁
	 * @param unionCode
	 */
	public void unlock(String unionCode) {
		Awaiter awaiter = awaiters.get(unionCode);
		if(awaiter == null) return;
		Lock lock = awaiter.getLock();
		lock.lock();
		awaiter.getCondition().signal();
		lock.unlock();
		awaiters.remove(unionCode);
	}
	
	/**
	 * 启动扫描器
	 */
	final public void start() {
		isRunning = true;
		
		//扫描
		service.execute(new Runnable() {
			@Override
			public void run() {
				while(isRunning) {
					service.execute(new Runnable() {
						@Override
						public void run() {
							for(T t: scan()) {
								addRecord(getUnionCode(t), awaiters.get(getUnionCode(t)));
								unlock(getUnionCode(t));
							}
						}
					});
					
					try {
						Thread.sleep(scanIntervalWithMsec);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		
		//清除
		service.execute(new Runnable() {
			@Override
			public void run() {
				while(isRunning) {
					service.execute(new Runnable() {
						@Override
						public void run() {
							Set<String> codes = new HashSet<String>();
							
							for(Entry<String, Awaiter> entry: awaiters.entrySet()) {
								if(entry.getValue().getDateInterval() >= cleanIntervalWithMsec) {
									codes.add(entry.getKey());
									unlock(entry.getKey());
								}
							}
							
							clean(codes.toArray(new String[codes.size()]));
						}
					});
					
					try {
						Thread.sleep(cleanIntervalWithMsec);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
	}
	
	/**
	 * 停止扫描器
	 */
	final public void stop() {
		isRunning = false;
	}
	
	/**
	 * 添加记录，保存recordNumber条
	 * @param record
	 */
	private synchronized void addRecord(String code, Awaiter awaiter) {
		if(awaiter == null) return;
		if(records.size() >= recordNumber) {
			for(int i=0; i< records.size()-recordNumber+1; i++) {
				records.remove(0);
			}
		}
		
		records.add(new Record(code, awaiter.getDateInterval()));
	}
	
	
	/**
	 * 获取记录
	 * @return
	 */
	public List<Record> getRecords() {
		return records;
	}
	
	/**
	 * 获取Awaiters
	 * @return
	 */
	public Map<String, Awaiter> getAwaiters() {
		return awaiters;
	}
	
	
	/**
	 * 获取记录
	 * @return
	 */
	/*public String getRecords() {
		return JSON.toJSONString(records);
	}*/
	
	/**
	 * 获取Awaiters
	 * @return
	 */
	/*public String getAwaiters() {
		return JSON.toJSONString(awaiters);
	}*/
	
}
